Though the MTS extended, point source, and etalon data have their fair share of information to share, these are all optical stimuli placed outside of MIRI, observed during a test campaigns on-ground. As such they will not be available to be tested for repeatability during in-flight operations. Here we examine the MIRI internal calibration source observations. This source will also be observed periodically in-flight, thus understanding its behavior, as a "standard" of sorts, is important both in the context of flat-fielding the detector, but also in the context of MIRI fringes. Obviously the light from the MIRI calibration source will also yield a fringe spectrum.
from IPython.display import HTML
HTML('''<script>
code_show=true;
function code_toggle() {
if (code_show){
$('div.input').hide();
} else {
$('div.input').show();
}
code_show = !code_show
}
$( document ).ready(code_toggle);
</script>
The raw code for this IPython notebook is by default hidden for easier reading.
To toggle on/off the raw code, click <a href="javascript:code_toggle()">here</a>.''')
# import modules
import funcs
import mrsobs
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('presentation')
%matplotlib notebook
import warnings
warnings.simplefilter('ignore')
We load the images for one band of the MRS for different kinds of sources, including:
Additionally the pixel-to-wavelength calibration map and the pixel-to-along-slice position map are imported.
# Define paths to data
workDir = '/Users/ioannisa/Desktop/python/miri_devel/'
cdpDir = workDir+'cdp_data/'
d2cMapDir = workDir+'distortionMaps/'
lvl2path = workDir+'FM_data/LVL2/'
# Get data
band = '1A'
ext_source_sci,ext_source_bkg = mrsobs.FM_MTS_BB_extended_source(lvl2path,band,bb_temp='800K')
intcal_source_sci = mrsobs.MIRI_internal_calibration_source(lvl2path,band,campaign='FM')
point_source_sci_p1,point_source_bkg_p1 = mrsobs.FM_MTS_800K_BB_point_source_raster(lvl2path,position='middle',pointing='P3')
# Get wavelength calibration pixel map
d2cMaps = funcs.load_obj('d2cMaps_band{}'.format(band),path=d2cMapDir)
lambdaMap = d2cMaps['lambdaMap']
sliceMap = d2cMaps['sliceMap']
We subtract background exposures where available.
# perform transform
ext_source_bkgsubtr = ext_source_sci-ext_source_bkg
point_source_p1_bkgsubtr = point_source_sci_p1-point_source_bkg_p1
We perform an even-odd row signal correction to the data (caused by the read-out pattern of MIRI detector pixel rows).
ext_source_oddevencorr = funcs.OddEvenRowSignalCorrection(ext_source_bkgsubtr)
intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(intcal_source_sci)
point_source_p1_oddevencorr = funcs.OddEvenRowSignalCorrection(point_source_p1_bkgsubtr)
From MIRI design description report MIRI-DD-00001-AEU: "The calibration system consists of two identical calibration sources for flat-fielding the MIRIM detector array and for flat-fielding the spectrometer detector arrays. The blackbody radiation is produced by micro-miniature tungsten filament lamps and is rendered uniform by a diffusing surface within an optical concentrator. The light is then re-imaged to a pupil placed in the shadow of the secondary mirror."
fig,axs = plt.subplots(2,1,figsize=(10,8))
for row in [255,511,767]:
axs[0].plot(intcal_source_oddevencorr[row,:512],label='detector row {}'.format(row+1))
axs[1].plot(ext_source_oddevencorr[row,:512],label='detector row {}'.format(row+1))
axs[0].set_title('MIRI Internal Calibration Source')
axs[1].set_title('MTS Extended Source')
for plot in range(2):
axs[plot].set_ylim(0)
axs[plot].set_xlabel('Detector x-coordinate [pix]')
axs[plot].set_ylabel('Signal [DN/sec]')
axs[plot].legend(loc='lower center')
plt.tight_layout()
Read-out mode for all observations: NFRAME=1, NGROUP=20, NINT=5, READOUT=FAST
CV3_lvl2path = workDir+'CV3_data/LVL2/'
FM_lvl2path = workDir+'FM_data/LVL2/'
OTIS_lvl2path = workDir+'OTIS_data/MRS_RAD_11_CPT/'
CV3_intcal_source_sci = mrsobs.MIRI_internal_calibration_source(CV3_lvl2path,band,campaign='CV3')
FM_intcal_source_sci = mrsobs.MIRI_internal_calibration_source(FM_lvl2path,band,campaign='FM')
OTIS_intcal_source_sci = mrsobs.MIRI_internal_calibration_source(OTIS_lvl2path,band,campaign='OTIS')
CV3_intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(CV3_intcal_source_sci)
FM_intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(FM_intcal_source_sci)
OTIS_intcal_source_oddevencorr = funcs.OddEvenRowSignalCorrection(OTIS_intcal_source_sci)
row = 512
fig,axs = plt.subplots(2,1,figsize=(10,8))
axs[0].set_title('Detector row 512')
for plot in range(2):
axs[plot].plot(CV3_intcal_source_oddevencorr[row,:512],label='CV3 int cal source obs')
axs[plot].plot(FM_intcal_source_oddevencorr[row,:512],label='FM int cal source obs')
axs[plot].plot(OTIS_intcal_source_oddevencorr[row,:512],label='OTIS int cal source obs')
axs[plot].hlines(0,0,512,linestyle='dashed')
axs[plot].set_ylim(0)
axs[plot].set_xlabel('Detector x-coordinate [pix]')
axs[plot].set_ylabel('Signal [DN/sec]')
axs[plot].legend(loc='lower center')
axs[1].set_title('<Zoomed view>')
axs[1].set_xlim(15,40)
axs[1].set_ylim(0,630)
plt.tight_layout()
row = 512
plt.figure(figsize=(10,4))
plt.plot((FM_intcal_source_oddevencorr[row,:512]/CV3_intcal_source_oddevencorr[row,:512] -1)*100.,alpha=0.8,label='CV3 to FM obs')
plt.plot((OTIS_intcal_source_oddevencorr[row,:512]/FM_intcal_source_oddevencorr[row,:512] -1)*100.,label='FM to OTIS obs')
plt.plot((OTIS_intcal_source_oddevencorr[row,:512]/CV3_intcal_source_oddevencorr[row,:512] -1)*100.,alpha=0.4,label='CV3 to OTIS obs')
plt.hlines(0,0,512,linestyle='dashed')
plt.xlim(-25,522)
plt.ylim(-55,110)
plt.xlabel('Detector x-coordinate [pix]')
plt.ylabel('Percentage change [%]')
plt.legend(loc='upper right',fontsize=10,bbox_to_anchor=(1.25,0.6))
plt.tight_layout(rect=[0,0,0.83,1])
We use the straylight correction algorithm developed by Adrian Glauser (ETH Zurich) as a quick check on whether the differentiating background between test campaigns could be due to different levels of straylight.
CV3_intcal_source_straylightcorr = funcs.straylightCorrection(CV3_intcal_source_oddevencorr,sliceMap)
FM_intcal_source_straylightcorr = funcs.straylightCorrection(FM_intcal_source_oddevencorr,sliceMap)
OTIS_intcal_source_straylightcorr = funcs.straylightCorrection(OTIS_intcal_source_oddevencorr,sliceMap)
row = 512
fig,axs = plt.subplots(2,1,figsize=(10,8))
axs[0].set_title('Detector row 512')
for plot in range(2):
axs[plot].plot(CV3_intcal_source_straylightcorr[row,:512],label='CV3 int cal source obs')
axs[plot].plot(FM_intcal_source_straylightcorr[row,:512],label='FM int cal source obs')
axs[plot].plot(OTIS_intcal_source_straylightcorr[row,:512],label='OTIS int cal source obs')
axs[plot].hlines(0,0,512,linestyle='dashed')
axs[plot].set_ylim(-100)
axs[plot].set_xlabel('Detector x-coordinate [pix]')
axs[plot].set_ylabel('Signal [DN/sec]')
axs[plot].legend(loc='upper right',fontsize=10,bbox_to_anchor=(1.25,0.6))
axs[1].set_title('<Zoomed view>')
axs[1].set_xlim(15,40)
axs[1].set_ylim(0,630)
plt.tight_layout(rect=[0,0,0.83,1])
plt.figure(figsize=(10,4))
plt.plot((FM_intcal_source_straylightcorr[row,:512]/CV3_intcal_source_straylightcorr[row,:512] -1)*100.,alpha=0.8,label='CV3 to FM obs')
plt.plot((OTIS_intcal_source_straylightcorr[row,:512]/FM_intcal_source_straylightcorr[row,:512] -1)*100.,label='FM to OTIS obs')
plt.plot((OTIS_intcal_source_straylightcorr[row,:512]/CV3_intcal_source_straylightcorr[row,:512] -1)*100.,alpha=0.4,label='CV3 to OTIS obs')
plt.hlines(0,0,512,linestyle='dashed')
plt.xlim(-25,522)
plt.ylim(-55,110)
plt.xlabel('Detector x-coordinate [pix]')
plt.ylabel('Percentage change [%]')
plt.legend(loc='upper right',fontsize=10,bbox_to_anchor=(1.25,0.6))
plt.tight_layout(rect=[0,0,0.83,1])
To ensure that we are looking at the same spatial position of the calibration source illumination, we base our detector pixel tracing on a point source observation rather than the d2c along-slice information.
# pixel trace
ypos_p,xpos_p = funcs.detpixel_trace_compactsource(point_source_p1_oddevencorr,band,d2cMaps)
# signal normalization based on fringe profile
sel = lambdaMap[ypos_p,xpos_p]!=0
intcal_source_norm = funcs.norm_fringe(intcal_source_sci[ypos_p,xpos_p][sel],thres=0.,min_dist=6,k=3,ext=3)
ext_source_norm = funcs.norm_fringe(ext_source_oddevencorr[ypos_p,xpos_p][sel],thres=0.,min_dist=6,k=3,ext=3)
fig,axs = plt.subplots(3,1,figsize=(10,13))
axs[0].set_title('Internal Calibration Source spectrum')
axs[0].plot(lambdaMap[ypos_p,xpos_p][sel],intcal_source_norm[0])
axs[0].plot(lambdaMap[ypos_p,xpos_p][sel][intcal_source_norm[1]],intcal_source_norm[0][intcal_source_norm[1]],'ro')
axs[0].plot(lambdaMap[ypos_p,xpos_p][sel],intcal_source_norm[2])
axs[0].set_ylim(350,830)
axs[0].set_ylabel('Signal [DN/sec]')
for plot in range(1,3):
axs[plot].plot(lambdaMap[ypos_p,xpos_p][sel],intcal_source_norm[0]/intcal_source_norm[2],label='Internal Calibration Source')
axs[plot].plot(lambdaMap[ypos_p,xpos_p][sel],ext_source_norm[0]/ext_source_norm[2],label='MTS Extended Source')
axs[plot].hlines(1,4.88,5.77,linestyle='dashed')
axs[plot].set_ylim(0.7,1.05)
axs[plot].set_ylabel('Normalized signal')
axs[1].legend(loc='upper right',bbox_to_anchor=(0.65,1.08),fontsize=10)
axs[2].hlines([0.795,0.912],4.88,5.77,'r',alpha=0.4,linestyle='dashed')
axs[2].set_xlim(5.14,5.31)
axs[2].set_title('<Zoomed view>')
for plot in range(3): axs[plot].set_xlabel('Wavelength [micron]')
plt.tight_layout()
What could be causing the difference in contrast between the fringes of the MIRI internal calibration source and that of the MTS extended source?